using MultiAgentsClient.ChatDataStructures;
using MultiAgentsShared;
using static MultiAgentsClient.Manager.MessageManager;
using static MultiAgentsClient.Presentation.Component.ChatInputBox;
using static MultiAgentsClient.Presentation.MentionableModel;

namespace MultiAgentsClient.Presentation;

public partial record ChatInputBoxModel
{
    private readonly EventBus eventBus;

    public int SelectedMentionableIndex = 0;

    public IState<bool> IsFilesDisplay => State.Value(this, () => false);
    public IState<bool> AllowToSendMessage => State.Value(this, () => true);
    public IState<bool> IsShiftKeyDown => State.Value(this, () => false);
    public IState<bool> IsControlKeyDown => State.Value(this, () => false);
    public IState<string> InputContent => State.Value(this, () => "");
    public IListState<WorkflowDisp> WorkflowsDisp => ListState<WorkflowDisp>.Empty(this);
    public IListState<string> InputFileList => ListState<string>.Empty(this);

    public record InputBoxTabKeyDownCommand();
    public record InputBoxUpKeyDownCommand();
    public record InputBoxDownKeyDownCommand();

    public ChatInputBoxModel()
    {
        eventBus = EventBus.Instance;

        eventBus.Subscribe<SendUserMessageCompleteCommand>(async cmd => { await SendUserMessageCompleteCommandHandler(cmd); });
        eventBus.Subscribe<SendToolResultCompleteCommand>(async cmd => { await SendToolResultCompleteCommandHandler(cmd); });
        eventBus.Subscribe<AllowSendMessageCommand>(async cmd => { await AllowSendMessageCommandHandler(cmd); });
        eventBus.Subscribe<SendUserMessageFailCommand>(async cmd => { await SendUserMessageFailCommandHandler(); });
        eventBus.Subscribe<FillAgentNameCommand>(async cmd => { await FillAgentNameCommandHandler(cmd); });
        eventBus.Subscribe<AddFileCommand>(async cmd => { await AddFileCommandHandler(cmd); });
    }

    public void StopChatMessage()
    {
        eventBus.Publish(new StopUserMessageCommand());
    }

    public async Task FillAgentNameCommandHandler(FillAgentNameCommand cmd)
    {
        string? inputStr = await InputContent;
        int atIndex = inputStr?.LastIndexOf('@') ?? -1;
        if (atIndex != -1)
        {
            inputStr = inputStr?[..(atIndex + 1)] ?? "";
        }
        inputStr = inputStr + cmd.MentionableAgentName + " ";
        await InputContent.Set(inputStr, default);
    }

    public async Task SendChatMessage()
    {
        string inputStr = await InputContent ?? string.Empty;

        IImmutableList<string> files = await InputFileList;
        if (string.IsNullOrEmpty(inputStr) && files.Count == 0)
        {
            return;
        }

        eventBus.Publish(new SendUserMessageCommand(inputStr, [.. files]));
    }

    public async Task TextBoxKeyboardKeyDownCommand(string key, CancellationToken ct)
    {
        if (key == "Enter" && await IsShiftKeyDown == false)
        {
            bool allowToSendMessage = await AllowToSendMessage;
            if (allowToSendMessage == false)
            {
                return;
            }
            await SendChatMessage();
        }
        else if (key == "Tab")
        {
            eventBus.Publish(new InputBoxTabKeyDownCommand());
        }
        else if (key == "Up")
        {
            eventBus.Publish(new InputBoxUpKeyDownCommand());
        }
        else if (key == "Down")
        {
            eventBus.Publish(new InputBoxDownKeyDownCommand());
        }
        else if (key == "TextChange")
        {
            await TextChangedCommand();
        }
        else if (key == "Shift")
        {
            await IsShiftKeyDown.SetAsync(true, ct: ct);
        }
        else if (key == "Control")
        {
            await IsControlKeyDown.SetAsync(true, ct: ct);
        }
        else if (key == "V")
        {
            if (await IsControlKeyDown)
            {
                await AddFileCommandHandler();
            }
        }
    }

    public async Task AddFileCommandHandler(AddFileCommand? cmd = null)
    {
        List<string> newAilePaths;
        List<string> files = [.. await InputFileList];

        if (cmd == null)
        {
            newAilePaths = ClipboardTool.GetClipboardFilePaths();
            
        }
        else
        {
            newAilePaths = cmd.FilePath;
        }

        foreach (string filePath in newAilePaths)
        {
            if (!files.Contains(filePath))
            {
                await InputFileList.AddAsync(filePath, default);
                await IsFilesDisplay.SetAsync(true);
            }
        }
    }

    public async Task TextChangedCommand()
    {
        string? currentText = await InputContent;

        if (currentText == null)
        {
            return;
        }
        eventBus.Publish(new RefreshMentionableListCommand(currentText));
    }

    public async Task RemoveInputFile(string fileName)
    {
        if (string.IsNullOrEmpty(fileName))
        {
            return;
        }

        await InputFileList.RemoveAllAsync(item => item == fileName, default);
        if ((await InputFileList).Count == 0)
        {
            await IsFilesDisplay.SetAsync(false);
        }
    }

    private async ValueTask SendUserMessageCompleteCommandHandler(SendUserMessageCompleteCommand cmd)
    {
        if (cmd.MentionedAgent == "")
        {
            await InputContent.Set("", default);
        }
        else
        {
            await InputContent.Set("@" + cmd.MentionedAgent + " ", default);
        }

        await InputFileList.RemoveAllAsync(item => true, default);
        await IsFilesDisplay.SetAsync(false);
    }

    private async Task SendUserMessageFailCommandHandler()
    {
        await AllowToSendMessage.Set(true, default);
    }

    private async ValueTask SendToolResultCompleteCommandHandler(SendToolResultCompleteCommand cmd)
    {
        await InputContent.Set(string.Empty, default);
    }

    private async ValueTask AllowSendMessageCommandHandler(AllowSendMessageCommand cmd)
    {
        await AllowToSendMessage.Set(cmd.IsAllow, default);
    }
}
